{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "70f24c79",
   "metadata": {},
   "source": [
    "| [02_advanced/03_高阶函数.ipynb](https://github.com/shibing624/python-tutorial/blob/master/02_advanced/03_高阶函数.ipynb)  | map、filter、lambda高阶函数  |[Open In Colab](https://colab.research.google.com/github/shibing624/python-tutorial/blob/master/02_advanced/03_高阶函数.ipynb) |\n",
    "\n",
    "# 高阶函数\n",
    "在 Python 中，函数是一种基本类型的对象，这意味着可以将函数作为参数传给另一个函数。\n",
    "\n",
    "将函数作为字典的值储存，将函数作为另一个函数的返回值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "4536f182",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cube 8\n",
      "square 4\n"
     ]
    }
   ],
   "source": [
    "def square(x):\n",
    "    \"\"\"Square of x.\"\"\"\n",
    "    return x * x\n",
    "\n",
    "\n",
    "def cube(x):\n",
    "    \"\"\"Cube of x.\"\"\"\n",
    "    return x * x * x\n",
    "\n",
    "\n",
    "# 函数的作为字典的值\n",
    "funcs = {'square': square, 'cube': cube, }\n",
    "x = 2\n",
    "for func in sorted(funcs):\n",
    "    print(func, funcs[func](x))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "776b4212",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'square'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "func"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "7c6a2fdd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'square': <function __main__.square(x)>, 'cube': <function __main__.cube(x)>}"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "funcs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63620819",
   "metadata": {},
   "source": [
    "## 函数参数\n",
    "引用传递\n",
    "\n",
    "传递给函数 f 的是一个指向 x 所包含内容的引用，\n",
    "如果我们修改了这个引用所指向内容的值（例如 x[0]=999），\n",
    "那么外面的 x 的值也会被改变："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e00c9bff",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def mod_f(x):\n",
    "    x[0] = 999\n",
    "    return x\n",
    "\n",
    "x = [1, 2, 3]\n",
    "\n",
    "x # [1, 2, 3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "3ea9746d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[999, 2, 3]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mod_f(x) # [999, 2, 3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "eebbf214",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[999, 2, 3]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x # [999, 2, 3]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ad406d3",
   "metadata": {},
   "source": [
    "过如果我们在函数中赋给 x 一个新的值（例如另一个列表），\n",
    "\n",
    "那么在函数外面的 x 的值不会改变："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "fa0d2469",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n",
      "[999, 2, 3]\n",
      "[999, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "def no_mod_f(x):\n",
    "    x = [4, 5, 6]\n",
    "    return x\n",
    "\n",
    "\n",
    "x = [1, 2, 3]\n",
    "\n",
    "print(x)\n",
    "print(mod_f(x))\n",
    "print(x)\n",
    "# [1, 2, 3]\n",
    "# [999, 2, 3]\n",
    "# [999, 2, 3]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba3693f4",
   "metadata": {},
   "source": [
    "\n",
    "## 高阶函数\n",
    "以函数作为参数，或者返回一个函数的函数是高阶函数，\n",
    "常用的例子有 map 和 filter 函数\n",
    "\n",
    "map(f, sq) 函数将 f 作用到 sq 的每个元素上去，并返回结果组成的列表，\n",
    "\n",
    "相当于：[f(s) for s in sq]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "a243bb6b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<map at 0x7fb004f6adf0>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "map(square, range(5))  # [0, 1, 4, 9, 16]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "93b93360",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 1, 4, 9, 16]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 外面套个list，强转为list类型，是为了打印出函数的值\n",
    "list(map(square, range(5)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "b5608376",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 2, 4]"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def is_even(x):\n",
    "    return x % 2 == 0\n",
    "\n",
    "\n",
    "list(filter(is_even, range(5)))  # [0, 2, 4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "b4a1afc1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 4, 16]"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(square, filter(is_even, range(5))))  # [0, 4, 16]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4bc51d25",
   "metadata": {},
   "source": [
    "reduce(f, sq) 函数接受一个二元操作函数 f(x,y)，\n",
    "并对于序列 sq 每次合并两个元素："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "b839abf2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from functools import reduce\n",
    "def my_add(x, y):\n",
    "    return x + y\n",
    "\n",
    "\n",
    "reduce(my_add, [1, 2, 3])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4118d2e7",
   "metadata": {},
   "source": [
    "返回一个函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "0a6b25bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_logger_func(target):\n",
    "    def write_logger(data):\n",
    "        with open(target, 'a') as f:\n",
    "            f.write(data + '\\n')\n",
    "\n",
    "    return write_logger\n",
    "\n",
    "\n",
    "fun_logger = get_logger_func('foo.txt')\n",
    "fun_logger('hello')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "cf116815",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 查看foo.txt 是否生成\n",
    "import os\n",
    "os.path.exists('foo.txt')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4eb9ad2b",
   "metadata": {},
   "source": [
    "## 匿名函数lambda"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "7a3dd9f0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 1, 4, 9, 16]"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(square, range(5)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "e47ba1af",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 1, 4, 9, 16]"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 用匿名函数替换为：\n",
    "list(map(lambda x: x * x, range(5)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0cb261da",
   "metadata": {},
   "source": [
    "\n",
    "匿名函数虽然写起来比较方便（省去了定义函数的烦恼），\n",
    "但是有时候会比较难于阅读："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "90c1904e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n"
     ]
    }
   ],
   "source": [
    "s1 = reduce(lambda x, y: x + y, map(lambda x: x ** 2, range(1, 3)))\n",
    "print(s1)  # 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "cd0f9124",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n"
     ]
    }
   ],
   "source": [
    "# 简单的写法：\n",
    "s2 = sum(x ** 2 for x in range(1, 3))\n",
    "print(s2)  # 5"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a97ec71",
   "metadata": {},
   "source": [
    "## global 变量\n",
    "\n",
    "要在函数中修改全局变量的值，需要加上 global 关键字："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "63f6bf89",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18\n",
      "18\n"
     ]
    }
   ],
   "source": [
    "x = 15\n",
    "\n",
    "def print_newx():\n",
    "    global x\n",
    "    x = 18\n",
    "    print(x)\n",
    "\n",
    "\n",
    "print_newx()\n",
    "print(x)\n",
    "\n",
    "# 18\n",
    "# 18"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "387d6bc2",
   "metadata": {},
   "source": [
    "如果不加上这句 global 那么全局变量的值不会改变："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "fc2b16c3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18\n",
      "15\n"
     ]
    }
   ],
   "source": [
    "x = 15\n",
    "\n",
    "\n",
    "def print_newx2():\n",
    "    x = 18\n",
    "    print(x)\n",
    "\n",
    "\n",
    "print_newx2()\n",
    "print(x)\n",
    "\n",
    "\n",
    "# 18\n",
    "# 15"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13b0a046",
   "metadata": {},
   "source": [
    "\n",
    "## 递归\n",
    "一般对于分治法，要用递归，不过在python中不怎么用，更高效的处理非波切利算法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "e4e231c6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]\n"
     ]
    }
   ],
   "source": [
    "def fib(n):\n",
    "    \"\"\"Fib without recursion.\"\"\"\n",
    "    a, b = 0, 1\n",
    "    for i in range(1, n + 1):\n",
    "        a, b = b, a + b\n",
    "    return b\n",
    "\n",
    "\n",
    "print([fib(i) for i in range(10)])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8c23ae05",
   "metadata": {},
   "source": [
    "本节完。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05822c90",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}